package YPTServerRegister

import(
	pb "git.oschina.net/YPTArch/ypt_service_discovery/etcd"
	"google.golang.org/grpc"
	"context"
	"encoding/json"
	"errors"
)

type DiscoveryClient struct {
	etcdEndsPoints []string
	kvClient pb.KVClient
	con *grpc.ClientConn
}

type EtcdRes struct{
	Addr Address
	Api ApiInfo
}

type EtcdResAll map[string] EtcdSavedData

var regsteredKeys []string  //注册的键
func init(){
	regsteredKeys = make([]string,0)
}

func NewDiscoveryClient(etcdEndPoints []string) (*DiscoveryClient , error){
	d := &DiscoveryClient{
		etcdEndsPoints:etcdEndPoints,
	}
	con ,err :=  grpc.Dial(simpleEtcdBalancer(etcdEndPoints),grpc.WithInsecure())
	if err != nil {
		return nil, err
	}
	d.con =con
	d.kvClient = pb.NewKVClient(con)


	return d ,nil
}

func (d *DiscoveryClient) rangeOne(key string)( *pb.RangeResponse, error){
	return d.get([]byte(key),[]byte{0})
}

func (d *DiscoveryClient) rangeAll() (EtcdResAll, error){
	results,err := d.get([]byte{0},[]byte{0})
	if err != nil {
		return EtcdResAll{} ,err
	}
	if results.Kvs == nil {
		return EtcdResAll{}, nil
	}
	re := EtcdResAll{}
	for _,v := range results.Kvs{
		var data EtcdSavedData
		if err := json.Unmarshal(v.Value,&data);err != nil{
			return EtcdResAll{}, err
		}
		re[string(v.Key)] = data
	}
	return re, nil
}

func (d *DiscoveryClient) RangeService(key string) (EtcdRes, error){

	canWatch := true//防止生成多个watch
	for _,v := range regsteredKeys{
		if v == key{//若已存在，则不添加watch
			canWatch = false
			break
		}
	}
	if canWatch{
		w , err := NewDiscWatchClient(d)
		if err != nil {
			return EtcdRes{}, err
		}
		regsteredKeys = append(regsteredKeys,key)
		go watch(key,d.kvClient,w.processDelete,w.processNew)
	}
	//TODO 第一次rangeService时，应该判断etcd中的host是否有效.
	//TODO  测试多个discovery key
	if v,ok := etcdResMap[key];ok{//已存在
		if len(etcdResMap[key].Addr) == 0 {
			return EtcdRes{}, errors.New("no availble endpoints")
		}

		return EtcdRes{
			Addr : choosenAddress(v.Addr),
			Api : v.Api,
		}, nil
	}

	results, err := d.get([]byte(key),[]byte{0})
	if err != nil {
		return EtcdRes{},err
	}
	if results.Kvs == nil {
		return EtcdRes{}, errors.New("no availble endpoints")
	}
	var raw EtcdSavedData
	if err := json.Unmarshal(results.Kvs[0].Value, &raw); err != nil{
		return EtcdRes{},err
	}
	etcdResMap[key] = &raw
	return EtcdRes{
		Addr : choosenAddress(raw.Addr),
		Api : raw.Api,
	}, nil

}

func (d *DiscoveryClient) get(start,end []byte) ( *pb.RangeResponse, error){
	req := &pb.RangeRequest{
		Key : start,
	}
	if len(end) != 1 && end[0] != 0{
		req.RangeEnd = end
	}
	results, err := d.kvClient.Range(context.Background(),req)
	if err != nil{
		return nil , err
	}
	return results,err

}